// Copyright (c) [Year] [name of copyright holder]
// [Software Name] is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2. 
// You may obtain a copy of Mulan PSL v2 at:
//          http://license.coscl.org.cn/MulanPSL2 
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
// See the Mulan PSL v2 for more details.

/*!
 * \autor captainpeng
 * \date 2019-12-20
 * \update 2019-12-20
 * \version 1.0
 * \copyright
 */

#ifndef MY_SHAREPTR_HPP
#define MY_SHAREPTR_HPP

#include"mystd.hpp"

namespace my{
    // 2019-12-20
    // 因为新的内存管理器，准备作一个新的指针类来模仿和代替标准库的
    // 与标准库不一样的是，sharePtr 使用 shareMemory 作为内存管理器
    template<typename ElementType>
    class sharePtr{
    private:
        using elementType = info_type_t<ElementType>;
        using elementPtr = info_ptr_t<ElementType>;
        using elementRef = info_ref_t<ElementType>;
        using elementConstRef = info_constRef_t<ElementType>;
        using elementConstPtr = info_constPtr_t<ElementType>;

        using memType = shareMemory<elementType>;
        
    public:
        elementPtr mValue;

    public:
        // sharePtr():mValue(nil<elementType>()){}
        sharePtr(elementPtr p = nil<elementType>()):
            mValue(memType::assign(p);)
        {}
        
        sharePtr(std::nullptr_t):mValue(nil<elementType>()){}
        sharePtr(const sharePtr & p):
            mValue(memType::assign(p.mValue))
        {}
        
        sharePtr(sharePtr && p){
            memType::exchange(mValue, p.mValue);
        }
	
        sharePtr & operator=(const sharePtr & p){
            if(this != &p){
                this->free();
                mValue = memType::assign(p.mValue);
            }
            return *this;
        }

        sharePtr & operator=(sharePtr && p){
            memType::exchange(mValue, p.mValue);
            return *this;
        }

        sharePtr & operator=(elementPtr p){
            mValue = memType::assign(p);
            return *this;
        }

        sharePtr & operator=(std::nullptr_t){
            this->free();
            mValue = nil<elementType>();
            return *this;
        }
	
        ~sharePtr(){ this->free(); }

        inline void alloc(){
            this->free();
            mValue = memType::alloc(1);
        }

        inline void free(){
            memType::free(mValue);
            mValue = nil<elementType>();
        }
	
        inline elementPtr get() const {
            return mValue;
        }

        void swap(sharePtr & p){
            memType::exchange(mValue, p.mValue);
        }

        explicit operator bool() const {
            return mValue != nil<elementType>();
        }
	
        inline elementRef operator*(){
            return *get();
        }

        inline elementConstRef operator*() const{
            return *get();
        }

        inline elementPtr operator->(){
            return get();
        }
        
        inline elementConstPtr operator->() const {
            return get();
        }
	
        sharePtr & operator++(){
            ++mValue;
            return *this;
        }

        sharePtr & operator--(){
            --mValue;
            return *this;
        }

        sharePtr operator++(int){
            sharePtr tmp(*this);
            ++mValue;
            return tmp;
        }

        sharePtr operator--(int){
            sharePtr tmp(*this);
            --mValue;
            return tmp;
        }
	
        inline sharePtr operator+(const std::ptrdiff_t i){
            return sharePtr(mValue+i);
        }

        inline sharePtr operator-(const std::ptrdiff_t i){
            return sharePtr(mValue-i);
        }

        elementType & operator[](const std::ptrdiff_t i){
            std::ptrdiff_t pos = intLib<std::ptrdiff_t>::abs(i);
            return mValue[pos];
        }
    };

    template<typename T>
    inline bool operator==(const sharePtr<T> & p,std::nullptr_t){
        return p.get() == nil<T>();
    }

    template<typename T>
    inline bool operator==(std::nullptr_t,const sharePtr<T> & p){
        return p.get() == nil<T>();
    }

    template<typename T>
    inline bool operator!=(const sharePtr<T> & p,std::nullptr_t){
        return p.get() != nil<T>();
    }

    template<typename T>
    inline bool operator!=(std::nullptr_t,const sharePtr<T> & p){
        return p.get() != nil<T>();
    }

    template<typename T>
    inline bool operator==(const sharePtr<T> & p1,const sharePtr<T> & p2){
        return p1.get() == p2.get();
    }

    template<typename T>
    inline bool operator!=(const sharePtr<T> & p1,const sharePtr<T> & p2){
        return !(p1 == p2);
    }
    
    template<typename T>
    inline bool operator>(const sharePtr<T> & p1,const sharePtr<T> & p2){
        return p1.get() > p2.get();
    }

    template<typename T>
    inline bool operator>=(const sharePtr<T> & p1,const sharePtr<T> & p2){
        return (p1 > p2) || (p1 == p2);
    }
    
    template<typename T>
    inline bool operator<(const sharePtr<T> & p1,const sharePtr<T> & p2){
        return !(p1 > p2);
    }

    template<typename T>
    inline bool operator<=(const sharePtr<T> & p1,const sharePtr<T> & p2){
        return (p1 < p2) || (p1 == p2);
    }

    template<typename T>
    inline void swap(sharePtr<T> & p1,sharePtr<T> & p2){
        p1.swap(p2);
    }
}

#endif
